package file

import (
	"io"
	"os"
	"path/filepath"
	"strings"

	"github.com/alexmullins/zip"
)

func ZipCompress(source, target string, password ...string) error {
	zipFile, err := os.Create(target)
	if err != nil {
		return err
	}

	defer zipFile.Close()

	zipWriter := zip.NewWriter(zipFile)
	defer zipWriter.Close()

	fileInfo, err := os.Stat(source)
	if err != nil {
		return err
	}

	var baseDir string

	if fileInfo.IsDir() {
		baseDir = filepath.Base(source)
	}

	return filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		header, err := zip.FileInfoHeader(info)
		if err != nil {
			return err
		}

		if len(password) > 0 {
			header.SetPassword(password[0])
		}

		if baseDir != "" {
			header.Name = filepath.Join(baseDir, strings.TrimPrefix(path, source))
		}

		if info.IsDir() {
			header.Name += "/"
		} else {
			header.Method = zip.Deflate
		}

		writer, err := zipWriter.CreateHeader(header)
		if err != nil {
			return err
		}

		if info.IsDir() {
			return nil
		}

		file, err := os.Open(path)
		if err != nil {
			return err
		}

		if _, err = io.Copy(writer, file); err != nil {
			return err
		}

		file.Close()

		return nil
	})
}

func ZipDecompress(source, target string, password ...string) error {
	reader, err := zip.OpenReader(source)
	if err != nil {
		return err
	}

	if err := os.MkdirAll(target, os.ModePerm); err != nil {
		return err
	}

	for _, file := range reader.File {
		if len(password) > 0 {
			file.SetPassword(password[0])
		}

		dir := filepath.Join(target, file.Name)
		if file.FileInfo().IsDir() {
			os.MkdirAll(dir, file.Mode())
			continue
		}

		closer, err := file.Open()
		if err != nil {
			return err
		}

		writer, err := os.OpenFile(dir, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
		if err != nil {
			return err
		}

		if _, err := io.Copy(writer, closer); err != nil {
			return err
		}

		closer.Close()
		writer.Close()
	}

	return nil
}